package com.fdb.efp.console.executor;

import com.fdb.basic.framework.core.constant.FlowExceptionType;
import com.fdb.basic.framework.core.exception.TerminateException;
import com.fdb.basic.framework.core.log.LogManager;
import com.fdb.basic.framework.core.threadpool.ExecuteRtnInfo;
import com.fdb.basic.framework.core.threadpool.ThreadPool;
import com.fdb.basic.framework.core.util.SpringContextUtils;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.efp.console.common.constance.FlowConstance;
import com.fdb.efp.console.common.service.Executor;
import com.fdb.efp.console.common.vo.EngineVO;
import com.fdb.efp.console.service.facade.InstFlowInfoService;
import com.fdb.efp.console.service.vo.InstFlowInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.concurrent.Callable;

/**
 * 
 * 流程执行工厂类
 * 
 * @author Cytus_
 * @since 2018年5月7日 下午9:11:25
 * @version 1.0
 *
 */		  
@Service("flowExecutorFactory")
public class FlowExecutorFactory {
	
	@Autowired
	@Qualifier("flowThreadPool")
	private ThreadPool threadPool;
	
	@Autowired
    @Qualifier("instFlowInfoService")
	private InstFlowInfoService instFlowInfoService;
	
	private static Logger logger = LoggerFactory.getLogger(FlowExecutorFactory.class);
	
	
	public void asyncExecuteEvent(EngineVO evo) throws Exception {
		logger.info("事件实例编号："+ evo.getEventInstanceId() +", 事件编号："+ evo.getEventId() +"进行异步事件调用");
		threadPool.add(new FlowExecutorThread(evo));
	}
	
	public EngineVO syncExecuteEvent(EngineVO evo) throws Exception {
		Executor executor = (Executor) SpringContextUtils.getBean("eventExecutor");
		logger.info("事件实例编号："+ evo.getEventInstanceId() +", 事件编号："+ evo.getEventId() +"进行同步事件调用");
		try {
		    return executor.execute(evo);
		} catch (TerminateException e) {
		    updateFlowStatusByFlowInstanceId(evo.getFlowInstanceId(), FlowConstance.FlOW_STATUS_TERMINATE);
		    if (e.getFlowExceptionType().isHighLevel(FlowExceptionType.FLOW)) {
		        throw new TerminateException("当前流程已终止:"+ e.getMessage(), e);
            }
		    logger.warn("事件实例编号："+ evo.getEventInstanceId() +", 事件编号："+ evo.getEventId() +"当前流程已终止!终止任务ID为:"+ evo.getTaskId());
		}
		return evo;
	}
	
	/**
	 * 
	 * 异步线程执行
	 * 
	 * @author Cytus_
	 * @since 2018年5月14日 下午2:43:27
	 * @version 1.0
	 *
	 */
	class FlowExecutorThread implements Callable<ExecuteRtnInfo> {
		
		private EngineVO evo;
		
		public FlowExecutorThread(EngineVO evo) {
			this.evo = evo;
		}

		@Override
		public ExecuteRtnInfo call() throws Exception {
			// 事件执行器
			Executor executor = (Executor) SpringContextUtils.getBean("eventExecutor");
			try {
			    executor.execute(evo);
			} catch (TerminateException e) {
			    updateFlowStatusByFlowInstanceId(evo.getFlowInstanceId(), FlowConstance.FlOW_STATUS_TERMINATE);
			    logger.warn("事件实例编号："+ evo.getEventInstanceId() +", 事件编号："+ evo.getEventId() +"当前流程已终止!终止任务ID为:"+ evo.getTaskId());
	            if (e.getFlowExceptionType().isHighLevel(FlowExceptionType.FLOW)) {
	                throw e;
	            }
			} 
			logger.info("事件实例编号："+ evo.getEventInstanceId() +", 事件编号："+ evo.getEventId() +"进行异步事件调用结束!");
			return new ExecuteRtnInfo(null, null, null, null, true);
		}
		
	}
	
	/**
	 * 更新流程状态
	 * @param instFlowId
	 * @param flowStatue
	 * @return
	 */
	public int updateFlowStatusByFlowInstanceId(String instFlowId, String flowStatue) {
	    if (StringUtil.isNotEmpty(instFlowId)) {
            InstFlowInfoVO vo = new InstFlowInfoVO();
            vo.setInstFlowId(instFlowId);
            vo.setInstFlowState(flowStatue);
            if (FlowConstance.FLOW_STATUS_END.equals(flowStatue) || FlowConstance.FlOW_STATUS_TERMINATE.equals(flowStatue)) {
                vo.setEndTime(TimeUtil.getCurrentDateTime());
            }
            LogManager.info(instFlowId, instFlowInfoService, "updateFlowStatusByFlowInstanceId");
            return instFlowInfoService.updateFlowStatusByFlowInstanceId(vo);
	    }
	    return -1;
	}
	
}
